/*
 * Copyright (c) 2013-2015 Charkey. All rights reserved.
 *
 * This software is the confidential and proprietary information of Charkey.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the agreements you entered into with Charkey.
 *
 * Charkey MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 * Charkey SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package cn.simastudio.talos.ucpaas.client;

import cn.simastudio.talos.ucpaas.utils.file.SimaFileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * Usage: HttpClientUtils
 *
 * @author Charkey
 * @date 2015/7/16 16:20
 */
public class HttpClientUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtils.class);

    /**
     * HttpClient GET请求，针对非多媒体文件(文本、JSON等)
     *
     * @param url 请求URL，参数封装
     * @return 响应字符串
     */
    public static String get(String url) {
        LOGGER.info("------------------------------HttpClient GET开始-------------------------------");
        LOGGER.info("GET {}", url);
        if (StringUtils.isBlank(url)) {
            LOGGER.error("GET请求不合法，请检查uri参数!");
            return null;
        }
        StringBuilder content = new StringBuilder();
        CloseableHttpClient httpClient = null;
        HttpGet httpGet = null;
        String respContent = null;
        try {
            // 创建GET请求
            httpClient = HttpClients.createDefault();
            httpGet = new HttpGet(url);
            // 提交GET请求
            HttpResponse response = httpClient.execute(httpGet);
            // 获取响应内容
            respContent = response(content, response, "GET");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (httpGet != null) {
                // 释放资源
                httpGet.releaseConnection();
            }
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("resp：{}", respContent);
        LOGGER.info("------------------------------HttpClient GET结束-------------------------------");
        return respContent;
    }

    /***
     * HttpClient GET请求，Header参数
     *
     * @param url   请求地址
     * @param name  参数名称
     * @param value 参数值
     * @return 响应字符串
     */
    public static String getMethod(String url, String name, String value) {
        LOGGER.info("------------------------------HttpClient GET开始-------------------------------");
        LOGGER.info("GET: {}", url);
        if (StringUtils.isBlank(url)) {
            LOGGER.error("GET请求不合法，请检查uri参数!");
            return null;
        }
        LOGGER.info("req: {} = {}", name, value);
        StringBuilder content = new StringBuilder();
        CloseableHttpClient httpClient = null;
        HttpGet httpGet = null;
        String respContent = null;
        try {
            // 创建GET请求
            httpClient = HttpClients.createDefault();
            httpGet = new HttpGet(url);
            httpGet.addHeader(name, value);
            // 提交GET请求
            HttpResponse response = httpClient.execute(httpGet);
            // 获取响应内容
            respContent = response(content, response, "GET");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (httpGet != null) {
                httpGet.releaseConnection();
            }
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("resp：{}", respContent);
        LOGGER.info("------------------------------HttpClient GET结束-------------------------------");
        return respContent;
    }

    /**
     * HttpClient GET请求，只针对于多媒体文件(图片、音频等)<br>
     * 请求成功后，会直接从对方服务器下载多媒体文件到本地磁盘，默认使用源文件名称
     *
     * @param url        请求URL，参数封装
     * @param targetPath targetPath为一个目录(默认文件名称)或targetPath为一个完整的文件路径(自定义文件名称)
     */
    public static void getMethod(String url, String targetPath) {
        LOGGER.info("------------------------------HttpClient GET开始-------------------------------");
        LOGGER.info("GET: {}", url);
        if (StringUtils.isBlank(url) || StringUtils.isBlank(targetPath)) {
            LOGGER.error("GET请求不合法，请检查uri或者targetPath参数!");
            return;
        }
        // if (!specified) {// 不指定，目录
        // if (!new File(targetPath).isDirectory()) {
        // throw new RuntimeException("targetPath不是一个有效的文件目录");
        // }
        // } else {// 指定，文件路径
        // if (new File(targetPath).isDirectory()) {
        // throw new RuntimeException("targetPath不是一个有效的文件路径");
        // }
        // }
        // 创建GET请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpResponse response = httpClient.execute(httpGet);
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();// 响应码
            String reasonPhrase = statusLine.getReasonPhrase();// 响应信息
            if (statusCode == 200) {// 请求成功
                // 文件保存的绝对路径
                String filePath = targetPath;
                File file = new File(targetPath);
                if (file.isDirectory()) {// 使用默认文件名称
                    // 获取文件名称
                    Header[] header = response.getHeaders("Content-disposition");
                    String fileName = "";
                    if (header.length > 0) {
                        fileName = header[0].getValue();
                        fileName = fileName.substring(fileName.lastIndexOf("=") + 1, fileName.length()).replace("\"", "");
                    }
                    filePath = targetPath + File.separator + fileName;
                }
                // 获取响应MineType
                HttpEntity entity = response.getEntity();
                String MineType = entity.getContentType().getValue();
                LOGGER.info("MineType: {}", MineType);
                if (!MineType.startsWith("image")) {// 下载失败
                    LOGGER.error("resp: {}", EntityUtils.toString(entity));
                    return;
                }
                // 写入文件
                InputStream is = entity.getContent();
                SimaFileUtils.writeFile(is, filePath);
            } else {
                LOGGER.error("GET：code[{}], desc[{}]", statusCode, reasonPhrase);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            httpGet.releaseConnection();
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("------------------------------HttpClient GET结束-------------------------------");
    }

    /**
     * HttpClient POST请求，传参方式：二进制字节
     *
     * @param url    请求地址，该URL包含必要的参数
     * @param params 参数字符串
     * @return JSON字符串
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String postMethod(String url, String params) {
        LOGGER.info("------------------------------HttpClient POST开始-------------------------------");
        LOGGER.info("POST: {}", url);
        if (StringUtils.isBlank(url) || StringUtils.isBlank(params)) {
            throw new RuntimeException("POST请求不合法，请检查uri或者params参数!");
        }
        LOGGER.info("req: {}", params);
        StringBuilder content = new StringBuilder();
        String respContent = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        try {
            // 使用支持以输入流传参的参数实体接口
            BasicHttpEntity httpEntity = new BasicHttpEntity();
            httpEntity.setContent(new ByteArrayInputStream(params.getBytes("UTF-8")));
            httpPost.setEntity(httpEntity);
            // 提交post请求
            HttpResponse response = httpClient.execute(httpPost);
            // 获取响应内容
            respContent = response(content, response, "POST");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            httpPost.releaseConnection();
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("resp： {}", respContent);
        LOGGER.info("------------------------------HttpClient POST结束-------------------------------");
        return respContent;
    }

    /**
     * HttpClient POST请求 ,传参方式：key-value
     *
     * @param url    请求地址
     * @param params 参数列表
     * @return 响应字符串
     */
    public static String postMethod(String url, List<NameValuePair> params) {
        LOGGER.info("------------------------------HttpClient POST开始-------------------------------");
        LOGGER.info("POST: {}", url);
        if (StringUtils.isBlank(url)) {
            LOGGER.error("post请求不合法，请检查uri参数!");
            return null;
        }
        LOGGER.info("req: {}", params);
        StringBuilder content = new StringBuilder();
        // 创建GET请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        String respContent = null;
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            // 执行请求
            HttpResponse response = httpClient.execute(httpPost);
            // 获取响应内容
            respContent = response(content, response, "POST");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            httpPost.releaseConnection();
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("resp：{}", respContent);
        LOGGER.info("------------------------------HttpClient POST结束-------------------------------");
        return respContent;
    }

    /**
     * HttpClient POST请求 ,上传多媒体文件
     *
     * @param url      请求地址
     * @param filePath 多媒体文件绝对路径
     * @return 多媒体文件ID
     */
    @SuppressWarnings("resource")
    public static String postMethod2(String url, String filePath) {
        LOGGER.info("------------------------------HttpClient POST开始-------------------------------");
        LOGGER.info("POST: {}", url);
        LOGGER.info("filePath: {}", filePath);
        if (StringUtils.isBlank(url)) {
            LOGGER.error("post请求不合法，请检查uri参数!");
            return null;
        }
        StringBuilder content = new StringBuilder();

        // 模拟表单上传 POST 提交主体内容
        String boundary = "-----------------------------" + new Date().getTime();
        // 待上传的文件
        File file = new File(filePath);

        if (!file.exists() || file.isDirectory()) {
            LOGGER.error("{}:不是一个有效的文件路径", filePath);
            return null;
        }

        // 响应内容
        String respContent = null;

        InputStream is = null;
        OutputStream os = null;
        File tempFile = null;
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        try {
            // 创建临时文件，将post内容保存到该临时文件下，临时文件保存在系统默认临时目录下，使用系统默认文件名称
            tempFile = File.createTempFile(new SimpleDateFormat("yyyy_MM_dd").format(new Date()), null);
            os = new FileOutputStream(tempFile);
            is = new FileInputStream(file);

            os.write(("--" + boundary + "\r\n").getBytes());
            os.write(("Content-Disposition: form-data; name=\"media\"; filename=\"" + file.getName() + "\"\r\n").getBytes());
            //os.write(String.format("Content-Type: %s\r\n\r\n", FileUtils.getMimeType(file)).getBytes());

            // 读取上传文件
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buff = new byte[8096];
            int len = 0;
            while ((len = bis.read(buff)) != -1) {
                os.write(buff, 0, len);
            }

            os.write(("\r\n--" + boundary + "--\r\n").getBytes());

            httpClient = HttpClients.createDefault();
            // 创建POST请求
            httpPost = new HttpPost(url);

            // 创建请求实体
            FileEntity reqEntity = new FileEntity(tempFile, ContentType.MULTIPART_FORM_DATA);

            // 设置请求编码
            reqEntity.setContentEncoding("UTF-8");
            httpPost.setEntity(reqEntity);
            // 执行请求
            HttpResponse response = httpClient.execute(httpPost);
            // 获取响应内容
            respContent = response(content, response, "POST");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                close(tempFile, os, is, httpPost, httpClient);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LOGGER.info("resp： {}", respContent);
        LOGGER.info("------------------------------HttpClient POST结束-------------------------------");
        return respContent;
    }

    /**
     * 获取响应内容，针对MimeType为text/plan、text/json格式
     *
     * @param content  响应内容
     * @param response HttpResponse对象
     * @param method   请求方式 GET|POST
     * @return 转为UTF-8的字符串
     * @throws ParseException
     * @throws IOException
     */
    private static String response(StringBuilder content, HttpResponse response, String method) throws ParseException, IOException {
        StatusLine statusLine = response.getStatusLine();
        int statusCode = statusLine.getStatusCode();// 响应码
        String reasonPhrase = statusLine.getReasonPhrase();// 响应信息
        if (statusCode == 200) {// 请求成功
            HttpEntity entity = response.getEntity();
            LOGGER.info("MineType: {}", entity.getContentType().getValue());
            content.append(EntityUtils.toString(entity));
        } else {
            LOGGER.error("{}: code[{}], desc[{}]", method, statusCode, reasonPhrase);
        }
        return content.toString();
    }

    // 释放资源
    private static void close(File tempFile, OutputStream os, InputStream is, HttpPost httpPost, CloseableHttpClient httpClient) throws IOException {
        if (!tempFile.delete()) {
            tempFile.deleteOnExit();
        }
        SimaFileUtils.close(os, is);
        // 释放资源
        httpPost.releaseConnection();
        httpClient.close();
    }
}